package com.xiaobai.stream_practice;

import com.xiaobai.stream_practice.entity.Author;
import com.xiaobai.stream_practice.entity.Book;
import org.junit.jupiter.api.Test;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author wangtw
 * @ClassName StreamOperate
 * @description: Stream流操作测试类
 * @date 2024/2/1511:54
 */
public class StreamOperate {

    @Test
    public void filterTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        Stream<Author> stream = authorData.stream();
        stream = stream.filter(a -> a.getAge() > 30);
        stream.forEach(a -> System.out.println(a));
    }

    @Test
    public void distinctTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        Stream<Author> stream = authorData.stream();
        stream = stream.distinct();
        stream.forEach(author -> System.out.println(author));
    }

    @Test
    public void sortedTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        Stream<Author> stream = authorData.stream();
        // 这里Author实体类实现了Comparable接口，重写了compareTo方法
        stream = stream.sorted();
        stream.forEach(author -> System.out.println(author));

        // 根据其它属性排序
        Stream<Author> stream1 = authorData.stream();
        stream1.sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())).forEach(author -> System.out.println(author));
    }

    @Test
    public void mapTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        Stream<Author> stream = authorData.stream();
        stream.map(author -> author.getRealName()).forEach(name -> System.out.println(name));
    }

    @Test
    public void flatMap() {
        List<Author> authorData = PrepareWork.getAuthorData();

        Stream<Author> stream = authorData.stream();

        // 映射的时候需要判断每个author的bookList是否为空
        stream.flatMap(author -> ObjectUtils.isEmpty(author.getBookList())
                        ? Collections.EMPTY_LIST.stream() : author.getBookList().stream())
                .forEach(book -> System.out.println(book));
    }

    @Test
    public void limitTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        // 获取前5条的数据
        Stream<Author> stream = authorData.stream();
        stream.limit(5).forEach(author -> System.out.println(author));
    }

    @Test
    public void skipTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        Stream<Author> stream = authorData.stream();
        // 获取集合中第三条和第四条数据
        stream.skip(2).limit(2).forEach(author -> System.out.println(author));
    }

    @Test
    public void forEachTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        // 遍历所有元素
        authorData.stream().forEach(author -> System.out.println(author));
    }

    @Test
    public void countTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        long count = authorData.stream().count();
        System.out.println(count);
    }

    @Test
    public void maxMinTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        // 获取年龄最大的作者
        Optional<Author> max = authorData.stream().max((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge()));
        // 安全获取Optional的值
        System.out.println(max.orElseGet(() -> new Author()));

        // 获取工资最低的作者
        Optional<Author> min = authorData.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        // 安全获取Optional的值
        System.out.println(min.orElseGet(() -> new Author()));
    }

    @Test
    public void anyMatchTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        boolean match = authorData.stream().anyMatch(author -> author.getAge() <= 30);
        System.out.println(match);
    }

    @Test
    public void allMatch() {
        List<Author> authorData = PrepareWork.getAuthorData();

        boolean allMatch = authorData.stream().allMatch(author -> author.getAge() <= 30);
        System.out.println(allMatch);
    }

    @Test
    public void noneMatch() {
        List<Author> authorData = PrepareWork.getAuthorData();

        boolean noneMatch = authorData.stream().noneMatch(author -> author.getAge() > 100);
        System.out.println(noneMatch);
    }

    @Test
    public void findAnyTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        Optional<Author> authorOptional = authorData.stream().filter(author -> author.getAge() > 30).findAny();
        System.out.println(authorOptional.orElseGet(() -> new Author()));
    }

    @Test
    public void findFirstTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        Optional<Author> authorOptional = authorData.stream().filter(author -> author.getAge() > 30).findFirst();
        System.out.println(authorOptional.orElseGet(() -> new Author()));
    }

    @Test
    public void reduceTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        // 计算所有工资总和
        Double sum = authorData.stream().map(author -> author.getSalary())
                .reduce((double) 0, (s1, s2) -> s1 + s2);
        System.out.println(sum);

        Optional<Double> sumOptional = authorData.stream().map(author -> author.getSalary())
                .reduce((s1, s2) -> s1 + s2);
        sumOptional.orElseGet(() -> 0D);
    }

    @Test
    public void collectTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        // 将所有作者的名字转换成List
        List<String> realNameList = authorData.stream().map(author -> author.getRealName())
                .collect(Collectors.toList());

        // 将所有作者按照工资进行分组
        Map<Double, List<Author>> authorMap = authorData.stream().collect(Collectors.groupingBy(author -> author.getSalary()));
    }

    @Test
    public void parallelTest() {
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // 串行流转并行流并计算
        Integer sum1 = stream.parallel()
                .peek(num -> System.out.println(Thread.currentThread().getName() + "：" + num))
                .filter(num -> num > 5)
                .reduce((n1, n2) -> n1 + n2)
                .get();
        System.out.println(sum1);

        // 直接获取并行流
        Integer sum2 = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).parallelStream()
                .peek(num -> System.out.println(Thread.currentThread().getName() + "：" + num))
                .filter(num -> num > 5)
                .reduce((n1, n2) -> n1 + n2)
                .get();
        System.out.println(sum2);
    }

    @Test
    public void staticFunc() {
        List<Author> authorData = PrepareWork.getAuthorData();

        // 获取年龄的字符串集合，使用String.valueOf转换
        List<String> ageList = authorData.stream().map(author -> author.getAge())
                .map(age -> String.valueOf(age))
                .collect(Collectors.toList());

        // 年龄由整型转换成字符串时，使用静态方法引用
        List<String> ageList1 = authorData.stream().map(author -> author.getAge())
                .map(String::valueOf)
                .collect(Collectors.toList());
    }

    @Test
    public void funFunc() {
        List<Author> authorData = PrepareWork.getAuthorData();

        StringBuilder stringBuilder = new StringBuilder();
        authorData.stream().map(author -> author.getRealName())
                .forEach(name -> stringBuilder.append(name));
        System.out.println(stringBuilder.toString());

        // 使用对象的方法引用
        StringBuilder stringBuilder1 = new StringBuilder();
        authorData.stream().map(author -> author.getRealName())
                .forEach(stringBuilder1::append);
        System.out.println(stringBuilder1.toString());
    }

    @Test
    public void classFunc() {
        List<Author> authorData = PrepareWork.getAuthorData();

        // 排序，compareTo方法的调用者是抽象方法的第一个参数
        Collections.sort(authorData, new Comparator<Author>() {
            @Override
            public int compare(Author o1, Author o2) {
                return o1.compareTo(o2);
            }
        });
        // 优化
        Collections.sort(authorData, Author::compareTo);

        // 获取作者的姓名，getRealName方法的调用者时抽象方法的第一个参数
        Stream<String> stream = authorData.stream().map(new Function<Author, String>() {
            @Override
            public String apply(Author author) {
                return author.getRealName();
            }
        });
        // 优化
        Stream<String> stream1 = authorData.stream().map(Author::getRealName);

    }

    @Test
    public void structTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        Optional<Author> first = authorData.stream().findFirst();
        first.orElseGet(() -> new Author());

        // 优化：构造器引用（供给型接口）
        first.orElseGet(Author::new);

        // 函数式接口
        Function<String, Integer> function1 = Integer::new;
        // 数组构造引用
        Function<Integer, String[]> function2 = String[]::new;
    }

    @Test
    public void safeConsume() {
        List<Author> authorData = PrepareWork.getAuthorData();

        // 筛选
        Optional<Author> authorOptional = authorData.stream().filter(author -> author.getAge() > 40)
                .findFirst();

        // 安全消费
        authorOptional.ifPresent(System.out::println);
    }

    @Test
    public void safeGet() {
        List<Author> authorData = PrepareWork.getAuthorData();

        // 筛选
        Optional<Author> authorOptional = authorData.stream().filter(author -> author.getAge() > 100)
                .findFirst();

        // 安全获取值
        Author author = authorOptional.orElseGet(Author::new);
        System.out.println(author);

        Author author1 = authorOptional.orElseThrow(() -> new RuntimeException("获取值失败"));
        System.out.println(author1);
    }

    @Test
    public void optionalFilter() {
        List<Author> authorData = PrepareWork.getAuthorData();

        // 筛选
        Optional<Author> authorOptional = authorData.stream().filter(author -> author.getAge() > 30)
                .findFirst();

        // Optional筛选
        Optional<Author> author1 = authorOptional.filter(author -> author.getAge() > 40);
        System.out.println(author1.orElseGet(Author::new));
    }

    @Test
    public void optionalJudgeTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        // 筛选
        Optional<Author> authorOptional = authorData.stream().filter(author -> author.getAge() > 30)
                .findFirst();
        if (authorOptional.isPresent()) {
            System.out.println(authorOptional.get());
        }
    }

    @Test
    public void optionalMapTest() {
        List<Author> authorData = PrepareWork.getAuthorData();

        // 筛选
        Optional<Author> authorOptional = authorData.stream().filter(author -> author.getAge() > 40)
                .findFirst();

        // 转换
        Optional<List<Book>> books = authorOptional.map(Author::getBookList);
        System.out.println(books.orElseGet(ArrayList::new));
    }

}
